home *** CD-ROM | disk | FTP | other *** search
Java Source | 2000-09-28 | 7.4 KB | 237 lines | [TEXT/CWIE] |
- /*
- File: Buffer.java
-
- Copyright: © Copyright 1999-2000 Apple Computer, Inc. All rights reserved.
-
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
- ("Apple") in consideration of your agreement to the following terms, and your
- use, installation, modification or redistribution of this Apple software
- constitutes acceptance of these terms. If you do not agree with these terms,
- please do not use, install, modify or redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and subject
- to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
- copyrights in this original Apple software (the "Apple Software"), to use,
- reproduce, modify and redistribute the Apple Software, with or without
- modifications, in source and/or binary forms; provided that if you redistribute
- the Apple Software in its entirety and without modifications, you must retain
- this notice and the following text and disclaimers in all such redistributions of
- the Apple Software. Neither the name, trademarks, service marks or logos of
- Apple Computer, Inc. may be used to endorse or promote products derived from the
- Apple Software without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or implied,
- are granted by Apple herein, including but not limited to any patent rights that
- may be infringed by your derivative works or by other works in which the Apple
- Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
- WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
- (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Change History (most recent first):
-
- */
-
-
- package com.apple.jens.radio;
-
- import java.io.*;
- import java.util.Vector;
-
-
- /** A buffer for raw binary data, including the methods to write to (fill) the buffer from
- an InputStream, and to read the data from the Buffer to an OutputStream.
-
- <p> This class manages the synchronization between a single writer (the DJ thread)
- and multiple readers (the Transmitter threads):
- <ul>
- <li> Multiple readers can access the buffer at once.
- <li> Only one writer can access it at once.
- <li> Read attempts will block while a Buffer is being written. (This prevents
- Transmitter threads from overtaking the DJ.)
- <li> However, a writer can replace the contents of a Buffer that's being read from --
- the current readers will get the old contents, though.
- (This prevents the DJ from getting blocked by a stuck (paused) Transmitter,
- since the DJ uses a ring of Buffers.)
- </ul>
-
- */
-
- class Buffer {
-
- // LIFECYCLE:
-
-
- public Buffer( String name ) {
- fBytes = new byte[sSize];
- fName = name;
- }
-
-
- public synchronized String toString( ) {
- return "Buffer["+fName+", "
- +((fLength+512)/1024)+"K"
- +( fReaders >0 ?", "+fReaders+" reader(s)" :"" )
- +( fWriting ?", 1 writer)" :"" )
- +"]";
- }
-
-
- // DATA ACCESS:
-
-
- /** Fills the buffer with data read from the stream (up to the maximum buffer size.)
- @return True if data was read, or false if at EOF */
- public boolean readFrom( InputStream in, int bitRate ) throws IOException {
- // Grab the fWriting flag, making sure that only one thread can write.
- // Note that this does not block if other threads are reading!
- int nReaders;
- synchronized(this) {
- if( fWriting )
- throw new IllegalStateException("Buffer already has a writer");
- fWriting = true;
- nReaders = fReaders;
- if( nReaders > 0 )
- Radio.WARN(1,this,"About to overwrite while already being read -- DJ overtook Transmitter");
- }
-
- fBitRate = bitRate;
- int bytesRead = -1; // number of bytes read
- byte[] bytes = null;
-
- try{
- // Allocate a new byte array for the data if there are any readers,
- // so as not to clobber the old data they're using:
- bytes = nReaders==0 ?fBytes :new byte[sSize];
-
- // Read the data from the stream into the buffer:
- bytesRead = read(in,bytes);
- }finally{
-
- synchronized(this) {
- // Update the stored length, and the byte array itself (unless we hit an error):
- fLength = Math.max(0,bytesRead);
- if( bytesRead >= 0 )
- fBytes = bytes;
-
- // Finally release fWriting and notify any blocked readers:
- fWriting = false;
- if( fReaders > 0 ) {
- LOG(3,"Notifying readers now that write is over");
- this.notifyAll();
- }
- }
- }
-
- return bytesRead > 0;
- }
-
-
- /** Similar to DataInputStream.readFully except that it doesn't require that
- the entire array be fully read (thus it will not throw EOFException).
- @return the number of bytes read; zero if at EOF */
- private static int read( InputStream in, byte[] bytes ) throws IOException {
- int n = 0;
- while (n < bytes.length) {
- int count = in.read(bytes, n, bytes.length - n);
- if (count < 0)
- break;
- n += count;
- }
- return n;
- }
-
-
- /** Writes the buffer's data to an OutputStream.
- @return The number of milliseconds of real time that this MP3 data represents. */
- public long writeTo( OutputStream out ) throws IOException, InterruptedException {
- byte[] bytes;
- int length;
- int bitRate;
-
- // Block until the buffer is written (to avoid overtaking the DJ thread),
- // then bump the number of readers:
- synchronized(this) {
- if(fWriting) {
- LOG(3,"Blocking in writeTo until writer finishes");
- while( fWriting ) {
- this.wait();
- }
- LOG(3,"Done blocking in writeTo");
- }
- fReaders++;
-
- bytes = fBytes;
- length = fLength;
- bitRate = fBitRate;
- }
-
- // Write the data:
- try{
- out.write(bytes,0,length);
- }finally{
- // Finally decrement the number of readers:
- synchronized(this) {
- fReaders--;
- }
- }
-
- return length * 8000 / (long)bitRate;
- }
-
-
- /** Returns the current length in bytes of the data in the Buffer. */
- public int getLength( ) {
- return fLength;
- }
-
-
- private void LOG( int level, String msg ) {
- Radio.LOG(level,this,msg);
- }
-
-
- // INSTANCE DATA:
-
-
- /** The buffer's name, for debugging/logging purposes */
- private final String fName;
-
- /** The data buffer. Only the first fLength bytes contain valid data. */
- private byte[] fBytes;
-
- /** The length of the valid data in fBytes. */
- private int fLength;
-
- /** The bitrate of the MP3 data in fBytes. */
- private int fBitRate;
-
- /** The number of threads reading from the buffer (in the writeTo method).
- Access is synchronized against 'this' */
- private int fReaders;
-
- /** True if a thread is writing to the buffer (in the readFrom method).
- Access is synchronized against 'this' */
- private boolean fWriting;
-
-
- // STATIC DATA:
-
-
- /** The size that will be used for newly created Buffers.
- This is initialized by Radio.main
- @see Radio#main */
- public static int sSize = 32768;
-
- }
-